這個章節主要是介紹各種 “值” 在使用時,需要注意的地方。
Tony 覺得主要的重點在
(上)
(下)
惡名昭彰的副作用。
只要使用 IEEE 754 的語言都會有,不是只有 JS。(真是追根究底,但讀起來有拖下水的感覺)
0.1 + 0.2 === 0.3; // false
0.1 + 0.2; //0.30000000000000004
以二進位浮點數字表示的 0.1 和 0.2 並不精確。這算不上是臭蟲,是無法避免的。
但整數是 OK 的。如果浮點數要確實運用,請使用ES6 的 .EPSILON 的方法。(請在書上翻閱)
就是肯定可以運算。安全的精準無誤的範圍。
2^53 -1。
9007199254740991 比九千兆大一點點。
ES6 有預先定義 Number.MAX_SAFE_INTERGER。
也定義了Number.MIN_SAFE_INTERGER,也就是 -(2^53-1)。
這種大數字一般是出現在處理資料庫的64位元 ID。64位元無法以 number 傳遞。所以必須要用 string 儲存和傳輸。
大數運算在未來的版本,可能會有支援。
Number.Integer();
ES6 規格
Number.Integer(42); // true
Number.Integer(42.000); // true
Number.Integer(42.3); // false
非 ES6 規格,可以用這個方法,再加上 polyfill。
if (!Number.isInteger) {
Number.isInteger = function(num) {
return typeof num == "number" && num % 1 == 0;
}
}
(小補充)
以下方法都可以看數字是否為浮點數。
var num = 42.3;
num % 1 != 0; // true
~~num != num; // true
num + ".0" != num; //true
(還有測試是否為安全整數,請看書)
有些運算要用位元來處理。最多 32 位元。
可以用|0,來對整數做強制轉型。之所以可以將上限 53 位元轉成 32 位元,是因為|本來就是用於 32 位元,與 0 做運算就是逐位元 no-op (no operation) 運算。
1|1; // 2
2|1; // 3,因為 10 + 1 = 11,就是 3。
null 是關鍵字,不是識別字。你不能把它當作變數然後指定值給他。
undefined 是識別字。
將值設定給 undefined。(不建議)。
是朋友,就不會覆寫 undefined。
undefined 是內建的識別字,持有內建的 undefined 值。也可以用 void 運算子取得。
var a = 42;
console.log( void a, a ); // undefined 42
實務上,void 0、void 1 和 undefined 沒有差異。
當需要確保運算式沒有結果(即使他有副作用)。
function doSomething() {
if (!APP.ready) {
return void setTimeout( doSomething, 100);
}
var result;
return result;
}
if (doSomething()) {
// 立即處理下個任務
}
NaN (not a number),無效的數字(invalid)、不合格的數字(failed)、壞掉的數字(bad)。
NaN 的型別是 number。
var a = 2 / "foo"; // NaN
typeof a === "number"; // true
NaN 不等於任何數,包含他自己。
var a = 2 / "foo"; // NaN
a == NaN; // false
a === NaN; // false
NaN !== NaN; // true
他是唯一一個非反身值(not reflexive)。
那要如何測試? 用內建的 isNaN 的方法。
但 isNaN() 有缺陷。
var a = 2 / "foo";
var b = "foo";
a; // NaN
b; // "foo"
window.isNaN(a); // true
window.isNaN(b); // true 他的確 not a number,但他不是 NaN 阿!
這個 Bug 存在 19 年了。
ES6 有替代的工具。Number.isNaN()
也可以用他的特性 NaN !== NaN 來辨別。
var a = 1 / 0; // Infinity
var b = -1/ 0; // -Infinity
要到達無限的階段,除了要大於容許的最大值,還要超過(約整至最接近值 round to nearest)。
var a = Number.MAX_VALUE; // 1.7976931348623157e+308
a + a; // Infinity
a + Math.pow( 2, 970 ); // Infinity
a + Math.pow( 2, 969 ); //1.7976931348623157e+308
成為無限之後的運算,幾乎不能回頭,成為無限就是無限,除了下列:
無限除以無限呢? NaN。
有限的 number 除以 無限呢? 0
負的有限 除以 無限?
JavaScript 的世界裡,有 -0 的存在。
為什麼需要 -0?
在某些特定應用,例如動畫設計,數值可以表示移動速度,正負號可以表示方向。
當你有這樣的特殊需求,需要辨別 0 和 -0 的差異,再看下面的敘述。
var a = 0 / -3; // -0
var b = 0 * -3; // -0
加法和減法不會產生 -0。
如果將 -0 轉成字串。會轉成 "0"。
a; // -0
a.toString(); // "0"
a + ""; // "0"
String(a); // "0"
JSON.stringify(a); // "0",JSON 也沒保留
但如果是從字串 "-0" 轉回成數字。就是 -0。
+"-0"; // -0
Number("-0"); // -0
JSON.parse("-0"); // -0
字串化會變,數值化不會變。運算子分不出來。
var a = 0; // 0
var b = 0 *-1; // -0
a == b; // true
a === b; // true
a > b; // false
若要更清楚的分辨 0 和 -0 的差異。
function isNegZero(n) {
n = Number(n);
return (n === 0) && (1/n === -Infinity);
// 值是零,且,有負號。
}
(接下來有關於 NaN 和 -0 判斷在 ES6 一勞永逸地方式,以及他的 polyfill 在書上有詳細的解說。)
私心推薦:好想工作室 小龜 同學
學JS的心路歷程 Day4 - 參數的傳遞方式(上)
看完再看這章,會更有體悟。
JavaScript 沒有指標。
var a = 2;
var b = a;
b++;
a; // 2
b; // 3
var c = [1,2,3];
var d = c;
d.push( 4 );
c; // [1,2,3,4]
d; // [1,2,3,4]